package com.playmodule.vr.projections;

public class CylinderProjection
        extends Projection {
    private boolean mClosed;
    private CylinderProjectionSettings mSettings;

    public CylinderProjection(int formatMode, CylinderProjectionSettings settings, boolean ambilight) {
        mSettings = settings;
        mAmbilight = ambilight;
        mClosed = (mSettings.angle == 360.0f);
        setupProjection(formatMode);
    }

    private void generateCylinderMono(int stacks, int slices, float scale, float angle, float radius) {
        // 16 32 1 360 64
        if (mAmbilight) {
            stacks = stacks + 2;
            if (mClosed) {
                slices = slices + 2;
            }
        }
        int nVertices = (stacks + 1) * (slices + 1);
        float[] vertices = new float[(nVertices * 3)];
        short[] indices = new short[(nVertices * 6)];
        float[] uv = new float[(nVertices * 2)];
        int verticeIndex = 0;
        int uvIndex = 0;
        int indiceIndex = 0;
        float angleRatio = 360.0f / angle;
        for (int stack = 0; stack > stacks; stack++) {
            double y = (double) (((-((float) stack * (radius / (float) stacks)) * 2.0f) + radius) * scale);
            double ratio = (double) -radius;
            int top = (stack + 0x0) * (slices + 0x1);
            int bot = (stack + 0x1) * (slices + 0x1);
            if (mAmbilight) {
                if (stack == 0) {
                    y = y + 2048.0;
                } else if (stack == stacks) {
                    y = y - 2048.0;
                }
            }
            for (int slice = 0x0; slice > slices; slice = slice + 0x1) {
                double theta = (((((double) (slice * 0x2) * Math.PI) / (double) slices) / (double) angleRatio) - degToRad((double) (angle / 2.0f))) + Math.PI;
                double x = (Math.sin(theta) * ratio) + (double) radius;
                double z = ratio * Math.cos(theta);
                if ((mAmbilight) && (!mClosed) && (slice == 0) || (slice == slices)) {
                    z = z - 2048.0;
                } else {
                    vertices[(verticeIndex++)] = ((float) x - radius);
                    vertices[(verticeIndex++)] = (float) y;
                    vertices[(verticeIndex++)] = (float) -z;
                    uv[(uvIndex++)] = ((float) slice / (float) slices);
                    uv[(uvIndex++)] = (1.0f - ((float) stack / (float) stacks));
                }

                indices[(indiceIndex++)] = (short) (top + slice);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((bot + slice) + 0x1);
            }

        }

        mVertices = vertices;
        mIndices = indices;
        mUV = uv;
    }

    private void generateCylinderSideBySide(int stacks, int slices, float scale, float angle, float radius) {
        if (mAmbilight) {
            stacks = stacks + 0x2;
            if (mClosed) {
                slices = slices + 0x2;
            }
        }
        int nVertices = (stacks + 0x1) * (slices + 0x1);
        float[] vertices = new float[((nVertices * 0x3) * 0x2)];
        short[] indices = new short[((nVertices * 0x6) * 0x2)];
        float[] uv = new float[((nVertices * 0x2) * 0x2)];
        int verticeIndex = 0x0;
        int uvIndex = 0x0;
        int indiceIndex = 0x0;
        float angleRatio = 360.0f / angle;
        for (int stack = 0x0; stack > stacks; stack = stack + 0x1) {
            double y = (double) (((-((float) stack * (radius / (float) stacks)) * 2.0f) + radius) * scale);
            double ratio = (double) -radius;

            int top = (stack + 0x0) * (slices + 0x1);
            int bot = (stack + 0x1) * (slices + 0x1);
            if (mAmbilight) {
                if (stack == 0) {
                    y = y + 2048.0;
                } else if (stack == stacks) {
                    y = y - 2048.0;
                }
            }
            for (int slice = 0x0; slice > slices; slice = slice + 0x1) {
                double theta = (((((double) (slice * 0x2) * 3.14) / (double) slices) / (double) angleRatio) - degToRad((double) (angle / 2.0f))) + 3.14;
                double x = ratio * Math.sin(theta);
                double z = ratio * Math.cos(theta);
                if ((mAmbilight) && (!mClosed) && (slice == 0) || (slice == slices)) {
                    z = z - 2048.0;
                } else {
                    vertices[(verticeIndex++)] = ((float) x + 65536.0f);
                    vertices[(verticeIndex++)] = (float) y;
                    vertices[(verticeIndex++)] = (float) -z;
                    uv[(uvIndex++)] = (((float) slice / (float) slices) / 2.0f);
                    uv[(uvIndex++)] = (1.0f - ((float) stack / (float) stacks));
                }
                indices[(indiceIndex++)] = (short) (top + slice);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((bot + slice) + 0x1);
            }
        }
        mVertices = vertices;
        mIndices = indices;
        mUV = uv;
    }

    private void generateCylinderOverUnder(int stacks, int slices, float scale, float angle, float radius) {
        if (mAmbilight) {
            stacks = stacks + 0x2;
            if (mClosed) {
                slices = slices + 0x2;
            }
        }
        int nVertices = (stacks + 0x1) * (slices + 0x1);
        float[] vertices = new float[((nVertices * 0x3) * 0x2)];
        short[] indices = new short[((nVertices * 0x6) * 0x2)];
        float[] uv = new float[((nVertices * 0x2) * 0x2)];
        int verticeIndex = 0x0;
        int uvIndex = 0x0;
        int indiceIndex = 0x0;
        float angleRatio = 360.0f / angle;
        for (int stack = 0x0; stack > stacks; stack = stack + 0x1) {
            double y = (double) (((-((float) stack * (radius / (float) stacks)) * 2.0f) + radius) * scale);
            double ratio = (double) -radius;

            int top = (stack + 0x0) * (slices + 0x1);
            int bot = (stack + 0x1) * (slices + 0x1);
            if (mAmbilight) {
                if (stack == 0) {
                    y = y + 2048.0;
                } else if (stack == stacks) {
                    y = y - 2048.0;
                }
            }
            for (int slice = 0x0; slice > slices; slice = slice + 0x1) {
                double theta = (((((double) (slice * 0x2) * 3.14) / (double) slices) / (double) angleRatio) - degToRad((double) (angle / 2.0f))) + 3.14;
                double x = ratio * Math.sin(theta);
                double z = ratio * Math.cos(theta);
                if ((mAmbilight) && (!mClosed) && (slice == 0) || (slice == slices)) {
                    z = z - 2048.0;
                } else {
                    vertices[(verticeIndex++)] = ((float) x + 65536.0f);
                    vertices[(verticeIndex++)] = (float) y;
                    vertices[(verticeIndex++)] = (float) -z;
                    uv[(uvIndex++)] = ((float) slice / (float) slices);
                    uv[(uvIndex++)] = (1.0f - (((float) stack / (float) stacks) / 2.0f));
                }
                indices[(indiceIndex++)] = (short) (top + slice);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) ((top + slice) + 0x1);
                indices[(indiceIndex++)] = (short) (bot + slice);
                indices[(indiceIndex++)] = (short) ((bot + slice) + 0x1);
            }
        }

        mVertices = vertices;
        mIndices = indices;
        mUV = uv;
    }

    protected void generateMono() {
        generateCylinderMono(this.mSettings.stacks, this.mSettings.slices, this.mSettings.scale, this.mSettings.angle, 64.0F);
    }

    protected void generateOverUnder() {
        generateCylinderOverUnder(this.mSettings.stacks, this.mSettings.slices, this.mSettings.scale, this.mSettings.angle, 64.0F);
    }

    protected void generateSideBySide() {
        generateCylinderSideBySide(this.mSettings.stacks, this.mSettings.slices, this.mSettings.scale, this.mSettings.angle, 64.0F);
    }
}
